{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# One Port Tiered Calibration"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Intro"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "A one-port network analyzer can be used to measure a two-port device, provided that the device is reciprocal. This is accomplished by performing two calibrations, which is why its called a *tiered* calibration. \n",
    "\n",
    "First, the VNA is calibrated at the test-port like normal. This is called the *first tier*. Next, the device is connected to the test-port, and a calibration is performed at the far end of the device, the *second tier*. A diagram is shown below,\n",
    "\n",
    "![box diagram](oneport_tiered_calibration/images/boxDiagram.svg)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "This notebook will demonstrate how to use [skrf](http://scikit-rf.org) to do a two-tiered one-port calibration.  We'll use  data that was taken to characterize a waveguide-to-CPW probe. So, for this specific example the diagram above looks like:\n",
    "\n",
    "![probe diagram](oneport_tiered_calibration/images/probe.svg)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Some Data "
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "The data  available is the folders `'tier1/'` and `'tier2/'`. "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "!ls {\"oneport_tiered_calibration/\"}"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "(if you dont have the git repo for these examples, the data for this notebook can be found [here](https://github.com/scikit-rf/scikit-rf/tree/master/doc/source/examples/metrology/oneport_tiered_calibration))\n",
    "\n",
    "In each folder you will find the two sub-folders, called `'ideals/' ` and `'measured/'`. These contain touchstone files of the calibration standards ideal and measured responses,  respectively. "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "!ls {\"oneport_tiered_calibration/tier1/\"}"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "The first tier is at waveguide interface, and consisted of the following set of standards\n",
    "\n",
    "* short \n",
    "* delay short\n",
    "* load\n",
    "* radiating open (literally an open waveguide)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "!ls {\"oneport_tiered_calibration/tier1/measured/\"}"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Creating Calibrations"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### Tier 1"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "First defining the calibration for *Tier 1*"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "import matplotlib.pyplot as plt\n",
    "\n",
    "import skrf as rf\n",
    "from skrf.calibration import OnePort\n",
    "\n",
    "%matplotlib inline\n",
    "\n",
    "rf.stylely()\n",
    "\n",
    "\n",
    "tier1_ideals = rf.read_all_networks('oneport_tiered_calibration/tier1/ideals/')\n",
    "tier1_measured = rf.read_all_networks('oneport_tiered_calibration/tier1/measured/')\n",
    "\n",
    "\n",
    "tier1 = OnePort(measured = tier1_measured,\n",
    "                ideals = tier1_ideals,\n",
    "                name = 'tier1',\n",
    "                sloppy_input=True)\n",
    "tier1"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Because we saved corresponding *ideal* and *measured* standards with identical names, the Calibration will automatically align our standards upon initialization. (More info on creating Calibration objects this can be found in [the docs](../../tutorials/Calibration.ipynb).)\n",
    "\n",
    "Similarly for the second tier 2,"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### Tier 2"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "tier2_ideals = rf.read_all_networks('oneport_tiered_calibration/tier2/ideals/')\n",
    "tier2_measured = rf.read_all_networks('oneport_tiered_calibration/tier2/measured/')\n",
    "\n",
    "\n",
    "tier2 = OnePort(measured = tier2_measured,\n",
    "                ideals = tier2_ideals,\n",
    "                name = 'tier2',\n",
    "                sloppy_input=True)\n",
    "tier2"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Error Networks"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Each one-port Calibration contains a two-port error network, that is determined from the calculated error coefficients. The error network for *tier1* models the VNA, while the error network for *tier2* represents the VNA **and** the DUT. These can be visualized through the parameter `'error_ntwk'`.\n",
    "\n",
    "\n",
    "For tier 1, "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "tier1.error_ntwk.plot_s_db()\n",
    "plt.title('Tier 1 Error Network')"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Similarly for tier 2, "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "tier2.error_ntwk.plot_s_db()\n",
    "plt.title('Tier 2 Error Network')"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## De-embedding the DUT"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "As previously stated, the error network for *tier1* models the VNA, and the error network for *tier2* represents the VNA+DUT. So to determine the DUT's response, we cascade the inverse S-parameters of the VNA with the VNA+DUT. \n",
    "\n",
    "$$ DUT = VNA^{-1}\\cdot (VNA \\cdot DUT)$$\n",
    "\n",
    "In skrf, this is done as follows"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "dut = tier1.error_ntwk.inv ** tier2.error_ntwk\n",
    "dut.name = 'probe'\n",
    "dut.plot_s_db()\n",
    "plt.title('Probe S-parameters')\n",
    "plt.ylim(-60,10)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "You may want to save this to disk, for future use, \n",
    "\n",
    "    dut.write_touchstone()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "!ls {\"probe*\"}"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": []
  }
 ],
 "metadata": {
  "anaconda-cloud": {},
  "kernelspec": {
   "display_name": "Python 3",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.7.5"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 1
}
